﻿// ## 2023/03/16 # 铃 # 修改AI的出征条件,现在AI城市区域内有敌人或建筑时时,只要敌人数量足够低,依然可以进攻.##
// ## 2023/03/12 # 铃 # 新增小城调度功能,并且战斗期间不允许小城市运输(大城市出逃不受影响),
// ## 2023/03/01 # 铃 #  新增小城运输功能,
// ## 2022/07/16 # 铃 # 自动内政开启后,关闭了所有情况下的城市训练.巡查.生产 以节约AI的行动力和资金,所有修改处均有注释 ##
// ## 2022/04/03 # 江东新风 # 前线玩家委任军团越权分封问题,登用逻辑调整 ##
// ## 2022/03/16 # 江东新风 # 玩家部队计算错误bug ##
// ## 2022/02/14 # 江东新风 # 部分常量中文化 ##
// ## 2022/02/13 # 江东新风 # ai针对ai的战术调整 ##
// ## 2021/11/15 # 江东新风 # 改善ai人才积极性 ##
// ## 2021/10/18 # 江东新风 # 部分变量汉化 ##
// ## 2021/10/01 # 江东新风 # namespace的韩文改成英文 ##
// ## 2020/11/10 # messi # 同步泽纳ai后方低于xx数量武将不会擅自移动 ##
/*
*** Notice
본 스크립트에 대한 재배포, 무단수정을 금지 합니다.
개선을 빙자한 잘라먹기, 덮어씌우기 방식의 별도 패치 역시 거부 합니다.
필요사항 경우 쪽지나 메일을 통해 요청을 주시면 검토 후 반영하겠습니다.

*** 제작
 keehl102 -	삼국지 도원결의	(https://cafe.naver.com/sam10)
	제르나 -	삼국지 공방		(https://cafe.naver.com/rtkbank)
			삼국지 도원결의	(https://cafe.naver.com/sam10)

*** 환경
	삼국지11 PK - PK2.1

*** History ***
--------------------------------------------------------------------
		작 업 자			| 수정 일자	|		작 업 내 용
--------------------------------------------------------------------
	keehl102- 도원결의		| 18.03.07	| 초기생성
	제르나	- 공방		| 19.01.01	| v1.0
									| 위임도시 무장이동 금지
	제르나	- 공방		| 20.09.17	| v1.1
									| 인코딩 변경
	제르나	- 공방		| 20.10.18	| v1.2
									| AI 후방지역 이동제한
*/

namespace AI_BUILDING_SET_ORDER
{

	class Main
	{
		// 수정: 제르나
		// 내용: AI 후방지역 무장이동 제한 - 도시 대 무장수 일정 % 미만의 경우 이동안함
		bool use_minimum_officer = true;
		int minimum_officer_rate = 25; // 비율: 1 ~ 100% ex) 총무장 20명, 도시 2개 상황에서 50% 설정 시 무장 수 5명 (20 / 2 * 0.50) 이하의 후방 도시는 이동안함
		bool 调试模式 = false;
		// bool 调试模式2 = true;
		bool 调试模式2 = false;
		Main()
		{
			pk::set_func(255, pk::func255_t(callback));
			// pk::bind(111, pk::trigger111_t(onTurnStart));
		}

		void callback(pk::ai_context @context, pk::building @building)
		{
			// pk::trace("func_255:" + (building.get_id()));
			int building_id = building.get_id();
			pk::ai_context_base @base = context.base[building_id];
			pk::force @force = pk::get_force(building.get_force_id());;
			pk::district @district0 = pk::get_district(building.get_district_id());
			//if (building_id == 城市_汝南) pk::trace(pk::format("func255_t 据点：{},district-ap：{},状态：{}",pk::get_new_base_name(building_id),district0.ap, base.status));
			// pk::district @district = pk::get_district(building.get_district_id());
			// if (building.get_district_id() == 6) return;
			if (调试模式)
			{
				for (int i = 0; i < 据点_末; ++i)
				{
					pk::ai_context_base @baset = context.base[i];
					string t = "ai_据点：" + pk::get_new_base_name(building_id) + ":" + pk::get_new_base_name(i) + "据点状态：" + baset.status + ",己方部队数：" + baset.num_own_units + ",敌方部队数：" + baset.num_enemy_units + ",玩家部队数:" + baset.num_player_units;
					pk::trace(t);
				}
				for (int i = 0; i < context.target_count; ++i)
				{
					// string t = "target_count:" + context.target_count;
					// type 1 攻击？ 2 防御？
					int target = context.target[i];
					string t = pk::get_new_base_name(building_id) + "，目标" + i + ":" + pk::get_new_base_name(target) + ",type:" + context.type[i] + ",已出征部队：";
					for (int j = 0; j < 16; ++j)
					{
						int unit_id = context.get_march_unit_id(i, j);
						if (pk::is_valid_unit_id(unit_id))
						{
							string tt = pk::decode(pk::get_name(pk::get_unit(unit_id)));
							t += j + ":" + tt + ",";
						}
					}

					pk::trace(t);
					/*
					pk::ai_target_info@ target_info = context._2164[i];
					if (target_info.target != -1)
					{
						string t = "target_count:" + context.target_count + "目标" + pk::get_new_base_name(target_info.target) + "类型：" + target_info.type;
						for (int j = 0; j < 16; ++j)
						{
							if (target_info.march_unit_id[j] != -1) t += "部队" + j + ":" + target_info.march_unit_id[j];
						}
						pk::trace(t);
					}*/
				}
			}

			bool 自动内政开关 = ch::get_auto_affairs_status(building);


		// **********************************独立的AI策略**************************************************************

			if (ai::base_in_range_enemy_troops[building.get_id()] > 0)
			{
				context.push_cmd(据点AI_据点迎击);
			}


			else if (ai::base_around_enemy_troops[building.get_id()] == 0 and ai::base_in_range_enemy_troops[building.get_id()] == 0)
				context.push_cmd(据点AI_据点迎击建筑);

			context.push_cmd(据点AI_据点撤退);



			if (pk::get_elapsed_months() > 8)
			{
				context.push_cmd(据点AI_安置流民);
				context.push_cmd(据点AI_加固城防);
				context.push_cmd(据点AI_买卖兵装);
				context.push_cmd(据点AI_买卖粮草);

								//context.push_cmd(据点AI_设置);
			}


// **********************************兵临城下的AI策略**************************************************************
			if (base.enemies_around3)
			{
				if (!building.is_player())
				{
					context.push_cmd(据点AI_紧急调度);
				}

				if (!building.is_player() and base.num_idle_officers > 0)
				{
					context.push_cmd(据点AI_募兵);
				}

				if (ch::get_set_p(0).get_mod_set(据点计略扩展_开关))
				{
					context.push_cmd(据点AI_计略攻心);
					context.push_cmd(pk::rand_bool(50) ? 据点AI_计略扰乱 : 据点AI_计略伪报);
					context.push_cmd(据点AI_计略火攻);
					context.push_cmd(据点AI_计略待劳);
				}

				context.push_cmd(据点AI_紧急动员);
				context.push_cmd(据点AI_民兵);
				if (ch::get_set_p(0).get_mod_set(据点计略扩展_开关)) context.push_cmd(据点AI_计略鼓舞);

				return;
			}

			// **********************************非兵临城下的AI策略**************************************************************
			// 调度指令是个召唤指令,所以放在最前面,也就是num_idle_officers判决之前.
			//  如果小城市武将不多,则执行调度
			// if (base.num_officers <= 5 and building_id >= 建筑_城市末 and building_id < 据点_末)
			// 	context.push_cmd(据点AI_小城召唤);

				// 有钱才能县城管理,有空县城管理,节约命令书
			int count = pk::get_gold(building) / 府兵系统::GOLD_COST - 1;
			if (!building.is_player())
			{
				for (int j = 0; j < 最大城市县城数; ++j)
				{
					int spec_id = ch::get_base_spec(building_id, j);
					if (ch::is_valid_spec_id(spec_id) and count >= 1)
					{
						auto spec_t = ch::get_spec_p(spec_id);
						int person_id = spec_t.person;

						if (spec_t.person == -1)
						{
							context.push_cmd(据点AI_县城管理);
							count -= 1;
						}
					}
				}
			}

				// 如果只有一个据点就不用了
			int 据点状态 = ai::base_statue[building.get_id()];
			if (ch::get_base_list(force).count > 1)
			{
				if (base.num_idle_officers >= 3 and ai::base_real_person[building.get_id()] > ai::base_want_person[building.get_id()] + 2)
					context.push_cmd(据点AI_据点调度);

				if (base.num_idle_officers >= 1)
				{
					context.push_cmd(据点AI_优化调度);
				}

			}


			pk::district @district = pk::get_district(building.get_district_id());
			int force_id = context.force.get_id();

			if (ch::get_force_p(force_id).attack_delay == 0 and pk::get_elapsed_months() > 6 and pk::get_troops(building) > 50000 and building.energy >= 120 and pk::get_food(building) > 80000)
				context.push_cmd(据点AI_联合军出征);

			// 整体优先级思路为,军事和调度优先,开发和内政其次,最后是登用.探索计略等.
			// 战斗据点才能防御
			// 战斗状态才能触发屏障建设,且屏障建设只能在一号
			if (base.status == 据点状态_战斗)
			{
				if (pk::get_day() == 1)
					context.push_cmd(据点AI_屏障建设);
			}

			// 出征判定之前,资金大于2000时,如果有低于98忠诚的先行褒奖
			if (pk::get_gold(building) > 2000 and pk::get_elapsed_months() > 1)
			{
				int 急需褒奖人数 = need_loyalty_count(building, 98);
				int 急需褒奖次数 = pk::min(急需褒奖人数, 3);

				for (int i = 0; i < 急需褒奖次数; ++i)
					context.push_cmd(据点AI_褒奖);
			}

			// 非战斗据点才能进攻
			// 大于30000兵,士气>100才触发进攻指令,节约命令书
			// 有时候会出现己方领地敌方建筑的情况,需要再考察
			// if (base.status != 据点状态_战斗 and pk::get_troops(building) > 20000 and building.energy > 100)
			// 有时候领地内出现贼封地的问题,导致攻击受阻,暂时取消.
			// 由于初期资源差距较大(兵力兵装.或者建设速度等),因此把进攻的保护期延长到8个月.第9个月才会进攻
			if (building_id >= 建筑_城市开始 and building_id < 建筑_城市末)
			{
				if (pk::get_elapsed_months() > 6 and pk::get_troops(building) > 30000 and building.energy >= 120 and pk::get_food(building) > 80000)
				{
					context.push_cmd(据点AI_增强出征);
					//context.push_cmd(据点AI_攻击);
				}
			}

			else if (pk::get_elapsed_months() > 6 and pk::get_troops(building) > 20000 and building.energy >= 120 and pk::get_food(building) > 50000)

			{
				context.push_cmd(据点AI_增强出征);
				//context.push_cmd(据点AI_攻击);
			}


			// 非战斗据点才能运输
			if (ai::base_in_range_enemy_troops[building.get_id()] == 0)
			{
				//每个城市有2次运输机会
				context.push_cmd(据点AI_据点运输);
				//context.push_cmd(据点AI_据点运输);
			}


		//if (building_id < 城市_末 and ai::base_real_person[building.get_id()] > ai::base_want_person[building.get_id()] + 3)
		//context.push_cmd(据点AI_移动);


		// if (!building.is_player() and base.status == 据点状态_后方)
		// context.push_cmd(据点AI_解除县城管理);

			// 只有大城市才有拆除.开发.合并.和生产
			if (building_id >= 建筑_城市开始 and building_id < 建筑_城市末)
			{
				// 战斗据点不拆除
				if (base.status != 据点状态_战斗)
					context.push_cmd(据点AI_拆除);

				// 开发次数取决于空地数量.
				if (ai::base_in_range_enemy_troops[building.get_id()] < 5000 and pk::get_gold(building) > 500)
				{
					pk::city @city = pk::building_to_city(building);
					int 空地数量 = city.max_devs - city.num_devs;
					// 保留一次开发次数,防止出现意外情况
					int开发次数 = 空地数量 == 0 ? 1 : pk::min(空地数量, 3);
					开发次数 = pk::max(开发次数, 1);

					for (int i = 0; i <= 开发次数; ++i)
						context.push_cmd(据点AI_开发);
				}

				// 如果开了三级设施,则节约一次命令书
#if param_set
				bool value = pk::get_dev_param().level3;
#endif
#if not_param_set
				bool value = bool(pk::core["facility_to_level3"]);
#endif
				if (!value)
					context.push_cmd(据点AI_吸收合并);

				// 内政
				if (!自动内政开关)
					context.push_cmd(据点AI_巡察);
				if (!自动内政开关)
					context.push_cmd(据点AI_征兵);
				if (!自动内政开关)
					context.push_cmd(据点AI_训练);
				if (!自动内政开关)
					context.push_cmd(据点AI_生产);

				if (!building.is_player())
					context.push_cmd(据点AI_扩建); // 因为扩建内部已经有是否可执行判断，所以这里可以在特定顺序下直接push,如果有更好的例外逻辑就在这之前加


				if (ai::base_around_enemy_troops[building.get_id()] == 0 and ai::base_in_range_enemy_troops[building.get_id()] == 0 and pk::get_elapsed_months() > 8)
				{
					if (ai::base_in_line_level[building.get_id()] < 3 and !ch::is_gate(building.get_id()))
					{
						if (pk::get_gold(building) > 5000 and ai::base_attacking_troops[building.get_id()] == 0)context.push_cmd(据点AI_修建设施);
						context.push_cmd(据点AI_解甲归田);
					}
				}



				// 探索登用
				// 后面还有多个项目,因此预留出足够的空间给后面的任务
				// 计算时用到了city属性,因此这里仅限于大城市
				if (need_officer(context, building))
				{
					int count1 = get_order_count_need(context, building, 据点AI_人才探索);
					count1 = pk::min(20 - context.num_orders, count1);
					for (int i = 0; i < count1; ++i)
						context.push_cmd(据点AI_人才探索);

					int count2 = get_order_count_need(context, building, 据点AI_武将登用);
					count2 = pk::min(23 - context.num_orders, count2);
					for (int i = 0; i < count2; ++i)
						context.push_cmd(据点AI_武将登用);

					int count3 = get_order_count_need(context, building, 据点AI_他势力武将登用);
					count3 = pk::min(25 - context.num_orders, count3);
					for (int i = 0; i < count3; ++i)
						context.push_cmd(据点AI_他势力武将登用);
				}

			}

			context.push_cmd(据点AI_人才探索);
			context.push_cmd(据点AI_武将登用);
			context.push_cmd(据点AI_他势力武将登用);
			// context.push_cmd(据点AI_交易);
			// context.push_cmd(据点AI_交易2);
			context.push_cmd(据点AI_计略);
			context.push_cmd(据点AI_计略破坏);
			context.push_cmd(据点AI_褒奖);

			// pk::trace(pk::format("2据点id：{}，命令书：{}", building_id, context.num_orders));

			// 剩下的所有都给探索,但不超过33次

			int 探索次数 = pk::min(35 - context.num_orders, 10);
			for (int i = 0; i <= 探索次数; ++i)
				context.push_cmd(据点AI_人才探索);
			// pk::trace(pk::format("3据点id：{}，命令书：{}", building_id, context.num_orders));



	// 관문, 항구

			if (调试模式2)
			{
				pk::ai_context_base @baset = context.base[building_id];
				string t = "ai_据点：" + pk::get_new_base_name(building_id) + ":" + "据点状态：" + baset.status + ",行动力：" + context.ap;
				for (uint32 i = 0; i < context.num_orders; ++i)
				{
					t += " " + i + ":" + ch::get_cmd_name(context.order_id[i]);
				}
				pk::trace(t);
			}
		}

		void onTurnStart(pk::force @force)
		{
			if (!force.is_player())
			{
				int month_bonus = pk::min(60, pk::get_elapsed_months() * 15);
				for (int i = 1; i < 9; ++i)
				{
					int district_id = pk::get_district_id(force, i);
					if (pk::is_valid_district_id(district_id))
					{
						pk::district @district = pk::get_district(district_id);
						if (pk::is_alive(district))
						{

							pk::add_ap(district, month_bonus);
						}
					}
				}
			}
		}
		/*
		由于地图对城市区划的划分有很多的交叉,或者有些城市本体距离自己边界太近或者太远
		会导致
		1.无关势力不小心路过自己的领地就被迎击,进入无效混战,由于多方都不以攻城为目的,所以消耗之后又撤退,导致无穷消耗,AI战线无法推进
		2.城市本体距离边界太近,走到城下才能紧急应急,很多时候已经错失时机.
		3.在自己领地附近有其他势力战斗
		等等
		因此重新划定了防御的策略和判断防御的标准
		 */
		bool check_can_defense(pk::ai_context_base @base, pk::building @building)
		{

			// 如果兵力不足,不要出城太远去迎击,只能等触发城下迎击逻辑
			int 总兵装 = pk::get_weapon_amount(building, 1) + pk::get_weapon_amount(building, 2) + pk::get_weapon_amount(building, 3) + pk::get_weapon_amount(building, 4);
			if (总兵装 < 15000 or pk::get_troops(building) < 15000 or pk::get_food(building) < 20000)
				return false;

		// 被兵临城下强制迎击
			if (building.get_id() < 城市_末 and base.enemies_around5)
				return true;

			// 被兵临城下强制迎击
			if (building.get_id() >= 城市_末 and base.enemies_around3)
				return true;

			pk::list<pk::unit @> unit_list = pk::get_unit_list();
			for (int i = 0; i < unit_list.count; i++)
			{
				pk::unit @unit = unit_list[i];
				if (!pk::is_alive(unit))
					continue;

				//  跳过非普通类型部队
				if (unit.type == 部队类型_运输)
					continue;

				//不去防御走栈道的部队
				pk::hex@ hex = pk::get_hex(unit.pos);
				if (hex.terrain == 地形_栈道)
					continue;


					// 境内或者距离内发现玩家单位则需要迎击.
				if (unit.is_player() and pk::get_building_id(unit.pos) == building.get_id())
					return true;

				if (unit.target_type == 部队任务对象_据点 and pk::is_valid_building_id(unit.target))
				{
					if (pk::get_building(unit.target).get_force_id() == building.get_force_id())
					{
						if (pk::get_building_id(pk::get_building(unit.target).pos) == building.get_id() and pk::get_building_id(unit.pos) == building.get_id())
							return true;
					}
				}

				if (unit.target_type == 部队任务对象_部队 and pk::is_valid_unit_id(unit.target))
				{
					if (pk::get_unit(unit.target).get_force_id() == building.get_force_id())
					{
						if (pk::get_building_id(pk::get_unit(unit.target).pos) == building.get_id() and pk::get_building_id(unit.pos) == building.get_id())
							return true;
					}
				}

				if (pk::is_valid_pos(unit.target_pos))
				{
				// 如果正在攻击己方建筑,且建筑距离比较近.则出兵防御
					@hex = pk::get_hex(unit.target_pos);
					if (hex.has_building)
					{
						pk::building @target_building = pk::get_building(unit.target_pos);
						if (target_building.get_force_id() == building.get_force_id() and (pk::get_building_id(target_building.pos) == building.get_id() or pk::get_building_id(unit.pos) == building.get_id()))
							return true;
					}

					// 如果正在攻击己方部队,且部队距离比较近.则出兵防御
					if (hex.has_unit)
					{
						pk::unit @target_unit = pk::get_unit(unit.target_pos);
						if (target_unit.get_force_id() == building.get_force_id() and (pk::get_building_id(target_unit.pos) == building.get_id() or pk::get_building_id(unit.pos) == building.get_id()))
							return true;
					}
				}
			}
			return false;
		}

		bool is_target_base(pk::ai_context @context, int src_building_id, int dst_building_id)
		{
			pk::ai_context_base @base = context.base[src_building_id];
			for (int i = 0; i < context.target_count; ++i)
			{
				if (context.type[i] == 1) // 类型1为攻击
				{
					int target = context.target[i];
					if (target == dst_building_id)
						return true;
				}
			}
			return false;
		}

		// 势力需要褒奖的人数
		int need_loyalty_count(pk::building @building, int loyalt_limit)
		{
			int src_force_id = building.get_force_id();
			auto src_force = pk::get_force(src_force_id);
			int loyalt_l = loyalt_limit;

			int need_loyalty_count = 0;

			pk::list<pk::person @> list_t = pk::get_person_list(src_force, pk::mibun_flags(身份_都督, 身份_太守, 身份_一般));

			for (int i = 0; i < list_t.count; ++i)
			{
				if (list_t[i].loyalty - loyalt_l < 0)
					need_loyalty_count++;
			}

			return need_loyalty_count;
		}

		// 本该改最小武将登用那块更合理，不过那样改动更大。既然效果一样，就在这里改好了
		bool need_officer(pk::ai_context @context, pk::building @building)
		{
			int building_id = building.get_id();
			pk::ai_context_base @base = context.base[building_id];
			// 原设定
			/*
			int need_num = 2 * pk::get_scenario().difficulty + 3;//难易度0-2
			if (base.num_officers < need_num) return true;
			return false;
			*/
			// 还是只对城市有效好了？
			int city_id = pk::get_city_id(building.get_pos());
			pk::city @city = pk::get_city(city_id);

			int office_need = 7 + 2 * pk::get_scenario().difficulty; // 难易度0-2
			int max_dst_officer = office_need;
			// 前线和警戒据点根据敌方武将数设定登用人才上限
			if (city !is null)
			{
				for (int i = 0; i < 6; ++i)
				{
					int dst_city_id = city.neighbor[i];
					if (pk::is_valid_city_id(dst_city_id))
					{
						pk::city @dst_city = pk::get_city(dst_city_id);
						if (pk::is_enemy(city, dst_city))
						{
							int person_count = pk::get_person_list(pk::city_to_building(dst_city), pk::mibun_flags(身份_君主, 身份_都督, 身份_太守, 身份_一般)).count;
							if (person_count > max_dst_officer)
								max_dst_officer = person_count;
						}
					}
				}
			}

			switch (base.status)
			{
				case 据点状态_后方:
					return (int(base.num_officers) < office_need);
				case 据点状态_警戒:
					return (int(base.num_officers) < max_dst_officer);
				case 据点状态_前线:
					return (int(base.num_officers) < max_dst_officer);
				case 据点状态_战斗:
					return (int(base.num_officers) < max_dst_officer);
				default:
					break;
			}
			return false;
		}

		// 研究发现，每次push一个指令都只会执行1次，所以针对未发现武将多，或者灭势力俘虏多的情况，加强对应指令数量
		int get_order_count_need(pk::ai_context @context, pk::building @building, int ai_order_id)
		{
			if (ai_order_id == 据点AI_人才探索)
			{
				int target_count = get_undetect_person_list(building).count;
				return pk::min(8, pk::max(0, int(ceil(target_count * 0.5f))));
			}
			else if (ai_order_id == 据点AI_武将登用)
			{
				int target_count = get_ai_employ_person_list(building).count;
				return pk::max(0, int(ceil(target_count * 0.5f)));
			}
			else if (ai_order_id == 据点AI_他势力武将登用)
			{
				int target_count = get_ai_employ_enemy_person_list(building).count;
				return pk::min(8, pk::max(0, int(ceil(target_count * 0.3f))));
			}
			return 1;
		}
		// 下面三个函数都是完全按照ai获取对应武将对象的函数复刻的
		pk::list<pk::person @> get_undetect_person_list(pk::building @building)
		{
			pk::list<pk::person @> list;
			for (int i = 0; i < 非贼武将_末; ++i)
			{
				pk::person @person = pk::get_person(i);
				if (pk::is_alive(person) and pk::is_undetect_person(person, building))
					list.add(person);
			}
			return list;
		}

		pk::list<pk::person @> get_ai_employ_person_list(pk::building @building)
		{
			pk::list<pk::person @> list;
			int src_force_id = building.get_force_id();
			int src_city_id = pk::get_city_id(building.pos);
			for (int i = 0; i < 非贼武将_末; ++i)
			{
				pk::person @person = pk::get_person(i);
				if (pk::is_alive(person) and person.get_force_id() != src_force_id)
				{
					bool is_same_base = false;
					if (person.mibun == 身份_在野) // 在野也是有所属所在的
					{
						pk::building @service_building = pk::get_building(person.service);
						if (pk::is_alive(service_building))
							is_same_base = (service_building.get_id() == src_city_id);
					}
					else if (person.mibun == 身份_俘虏)
					{
						is_same_base = (person.location == building.get_id());
					}
					if (is_same_base)
						list.add(person);
				}
			}
			return list;
		}

		pk::list<pk::person @> get_ai_employ_enemy_person_list(pk::building @building)
		{
			pk::list<pk::person @> list;
			int src_force_id = building.get_force_id();
			int src_city_id = pk::get_city_id(building.pos);
			auto src_force = pk::get_force(src_force_id);
			for (int i = 0; i < 非贼武将_末; ++i)
			{
				pk::person @person = pk::get_person(i);
				if (pk::is_alive(person))
				{
					if (person.mibun == 身份_一般 or person.mibun == 身份_太守 or person.mibun == 身份_都督)
					{
						if (!pk::is_absent(person))
						{
							int dst_force_id = person.get_force_id();
							if (pk::is_valid_normal_force_id(dst_force_id) and dst_force_id != src_force_id and !src_force.ally[dst_force_id]) // 正常势力，非己方势力，非盟友势力
							{
								if (!pk::is_valid_pos(person.get_pos()))
									continue;
								int dst_city_id = pk::get_city_id(person.get_pos());
								if (person.loyalty > 90)
								{
									if (src_city_id == dst_city_id)
									{
										list.add(person);
										continue;
									}
									if (pk::has_neighbor(pk::building_to_city(building), dst_city_id))
									{
										list.add(person);
										continue;
									}
								}
								else
								{
									if (src_city_id == dst_city_id)
									{
										list.add(person);
										continue;
									}
									int city_distance = pk::get_city_distance(src_city_id, dst_city_id);
									if (city_distance < 3)
									{
										list.add(person);
										continue;
									}
									if (city_distance == 3 and pk::rand_bool(25))
									{
										list.add(person);
										continue;
									}
								}
							}
						}
					}
				}
			}
			return list;
		}


		bool check_elite_unit(pk::unit @unit)
		{
			pk::equipment @equipment = pk::get_equipment(unit.weapon);
			uint8 elite_atk = uint8(equipment.stat[兵器能力_攻击] * 1.15f);
			uint8 elite_def = uint8(equipment.stat[兵器能力_防御] * 1.15f);
			if (elite_atk > unit.attr.stat[部队能力_攻击])
				return true;
			if (elite_def > unit.attr.stat[部队能力_防御])
				return true;
			return false;
		}

		array<array<int>> AI任务分数 = {
			{据点AI_开发, 0},
			{据点AI_征兵, 0},
			{据点AI_生产, 0},
			{据点AI_巡察, 0},
			{据点AI_交易, 0},
			{据点AI_训练, 0},
			{据点AI_防御, 0},
			{据点AI_攻击, 0},
			{据点AI_设置, 0},
			{据点AI_关卡运输, 0},
			{据点AI_都市运输, 0},
			{据点AI_移动, 0},
			{据点AI_人才探索, 0},
			{据点AI_武将登用, 0},
			{据点AI_他势力武将登用, 0},
			{据点AI_褒奖, 0},
			{据点AI_拆除, 0},
			{据点AI_计略, 0},
			{据点AI_交易2, 0},
			{据点AI_吸收合并, 0},
			{据点AI_计略破坏, 0},
			{据点AI_支援关卡, 0},
			{据点AI_县城管理, 0},
			{据点AI_解除县城管理, 0} };
	}

	Main main;
}